package com.fzhucc.modules.security.rest

import com.fzhucc.annotation.Log
import com.fzhucc.annotation.rest.AnonymousPostMapping
import com.fzhucc.exception.BadRequestException
import com.fzhucc.modules.security.config.WxProperties
import com.fzhucc.modules.security.config.bean.LoginProperties
import com.fzhucc.modules.security.config.bean.SecurityProperties
import com.fzhucc.modules.security.domain.OnlineUser
import com.fzhucc.modules.security.domain.dto.AuthDto
import com.fzhucc.modules.security.domain.dto.AuthWxUserDto
import com.fzhucc.modules.security.domain.dto.AuthWxUserRegisterDto
import com.fzhucc.modules.security.domain.dto.JwtUserDto
import com.fzhucc.modules.security.security.TokenProvider
import com.fzhucc.modules.security.service.AuthenticationService
import com.fzhucc.modules.security.service.OnlineUserService
import com.fzhucc.modules.security.util.WxUtils
import com.fzhucc.modules.system.repository.UserRepository
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import lombok.RequiredArgsConstructor
import lombok.extern.slf4j.Slf4j
import org.springframework.http.ResponseEntity
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import javax.annotation.Resource
import javax.servlet.http.HttpServletRequest
import javax.validation.Valid

/**
 * @author Woolsen
 * @since 2022/11/30 17:09
 */
@Slf4j
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
@Api(tags = ["系统：系统授权接口"])
class WxAuthorizationController(
    private val userRepository: UserRepository,
    private val properties: SecurityProperties,
    private val onlineUserService: OnlineUserService,
    private val tokenProvider: TokenProvider,
    private val authenticationService: AuthenticationService,
    @Resource
    private val loginProperties: LoginProperties,
    private val wxProperties: WxProperties,
) {

    @Log("微信网页扫码登录")
    @ApiOperation("微信网页扫码登录")
    @AnonymousPostMapping("login/wxh5")
    fun scanWxQRLogin(@RequestBody @Validated dto: AuthWxUserDto, request: HttpServletRequest): ResponseEntity<Any> {
        val wxToken = WxUtils.authH5Code(
            appId = wxProperties.h5.appId,
            appSecret = wxProperties.h5.appSecret,
            code = dto.code
        )
        val unionId = wxToken.unionId
//        val user = userRepository.findByUnionId(unionId)
//        if (user?.phone == null) {
//            throw BadRequestException(4001, "Unregister")
//        }
        val authentication = authenticationService.authenticateByUnionId(unionId)
        SecurityContextHolder.getContext().authentication = authentication
        val apiToken = tokenProvider.createToken(authentication)
        val jwtUserDto = authentication.principal
        // 保存在线信息
        onlineUserService.save(jwtUserDto, OnlineUser.SYSTEM, apiToken, request)
        // 返回 token 与 用户信息
        val authDto = AuthDto(
            properties.tokenStartWith + apiToken,
            jwtUserDto
        )
        if (loginProperties.isSingleLogin) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(authDto.user.username, apiToken)
        }
        return ResponseEntity.ok(authDto)
    }


    @Log("微信用户登录")
    @ApiOperation("微信登录授权")
    @AnonymousPostMapping(value = ["/wx/login", "login/mp"])
    fun wxLogin(@RequestBody @Valid dto: AuthWxUserDto, request: HttpServletRequest): ResponseEntity<Any> {
        //1.登录 传递code参数
        //2.存 unionid/openid  查用户表是否有这个用户
        //3.没有就返回状态码，让前端去注册
        //4.注册的时候选择角色身份  code 并登录
        val wxToken = WxUtils.authMpCode(
            appId = wxProperties.mp.appId,
            appSecret = wxProperties.mp.appSecret,
            code = dto.code
        )
        if (wxToken.unionId == null) {
            throw BadRequestException("UnionId为null")
        }
        val unionId = wxToken.unionId
        userRepository.findByUnionId(unionId)
            ?: return ResponseEntity.ok("unRegist")  //去注册选择角色
        val authentication: Authentication = authenticationService.authenticateByUnionId(unionId)
        SecurityContextHolder.getContext().authentication = authentication
        val apiToken = tokenProvider.createToken(authentication)
        val jwtUserDto = authentication.principal as JwtUserDto
        // 保存在线信息
        onlineUserService.save(jwtUserDto, OnlineUser.SYSTEM, apiToken, request)
        // 返回 token 与 用户信息
        val authDto = AuthDto(
            properties.tokenStartWith + apiToken,
            jwtUserDto
        )
        if (loginProperties.isSingleLogin) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(authDto.user.username, apiToken)
        }
        return ResponseEntity.ok(authDto)
    }

    @Log("微信用户注册登录")
    @ApiOperation("微信注册授权登录")
    @AnonymousPostMapping(value = ["/wx/regist", "/wx/register"])
    fun wxRegister(
        @RequestBody @Valid dto: AuthWxUserRegisterDto,
        request: HttpServletRequest,
    ): ResponseEntity<Any> {
        //4.注册的时候选择角色身份  code  并登录
        val wxToken = WxUtils.authMpCode(
            appId = wxProperties.mp.appId,
            appSecret = wxProperties.mp.appSecret,
            code = dto.code
        )
        if (wxToken.unionId == null) {
            throw BadRequestException("unionId为null")
        }
        val unionId = wxToken.unionId
        val user = userRepository.findByUnionId(unionId)
        if (user != null) {
            //去登录
            return ResponseEntity.ok("isRegist")
        }
        val authentication = authenticationService.authenticateByUnionId(unionId, dto.type)
        SecurityContextHolder.getContext().authentication = authentication
        val apiToken = tokenProvider.createToken(authentication)
        val jwtUserDto = authentication.principal as JwtUserDto
        // 保存在线信息
        onlineUserService.save(jwtUserDto, OnlineUser.SYSTEM, apiToken, request)
        // 返回 token 与 用户信息
        val authDto = AuthDto(
            properties.tokenStartWith + apiToken,
            jwtUserDto
        )
        if (loginProperties.isSingleLogin) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(authDto.user.username, apiToken)
        }
        return ResponseEntity.ok(authDto)
    }


}